java计算日期不包括周末、不包括节假日、不包括非工作时间、考虑加班时间

您所在的位置:网站首页 java 两个日期加减 java计算日期不包括周末、不包括节假日、不包括非工作时间、考虑加班时间

java计算日期不包括周末、不包括节假日、不包括非工作时间、考虑加班时间

2024-01-09 02:14| 来源: 网络整理| 查看: 265

需求:

1、给出开始时间beginDate,结束时间endDate,计算两个时间之间的时间差

2、给出一个时间nowDate,计算其加上x小时之后的时间。

注:

时间的计算不能计算非工作时间。即,不包括周末、不包括节假日、不包括非工作小时、考虑正常加班时间

例如:工作时间为:【8:00~12:00,14:00~18:00】

例如:国庆假期上班第一天10月9号是周日,这种情况时间也要计算在内

思路:

取开始时间,判断是否是节假日、是否是周末,是否是加班日

如果是节假日,开始日期往后延一天,然后再递归判断

如果是周末,判断是否是加班日,如果不是加班日,开始日期往后延一天,然后再递归判断

(看了有些网友写的方案计算两个日期的全部时间,然后再减去不符合条件的时间。我反其道而思考,只考虑符合条件的日期,求和,逻辑略复杂,但是直观易懂)

源码: public class DateCal { //法定节假日 private final String isHoliday = "1-1,1-2,1-3,2-9,2-10,2-11,2-12,2-13,2-14," + "2-15,4-4,4-5,4-6,4-29,4-30,5-1,6-10,6-11," + "6-12,9-19,9-20,9-21,10-1,10-2,10-3,10-4,10-5,10-6,10-7"; //节假日前后的加班 private final String isPlusDau = "10-8"; //工作时间 private final int morningBegin = 8;//上午开始时间 8点 private final int morningEnd = 12;//上午结束时间 12点 private final int afternoonBegin = 14;//下午开始时间 14点 private final int afternoonEnd = 18;//结束时间 18点 private final Logger logger = Logger.getLogger(DateCal.class); /** * @param args */ public static void main(String[] args) { try { String strDateStart = "2018-07-06 16:00:00"; String strDateEnd = "2018-07-09 16:40:10"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date_start = sdf.parse(strDateStart); Date date_end = sdf.parse(strDateEnd); DateCal app = new DateCal(); Calendar cal_start = Calendar.getInstance(); Calendar cal_end = Calendar.getInstance(); cal_start.setTime(date_start); cal_end.setTime(date_end); System.out.println(app.getPluseHourDate(date_start,15.5)); System.out.println(app.getMinusofTowDate(date_start,cal_end)); } catch (Exception e) { // TODO: handle exception } } //判断是否是法定节假日 private boolean isHodliDays(Calendar d1) { /* 关于法定节假日,这里还有一个问题需要提前考虑下 例如: 国庆10月1号到10月7号,那10月8号正式上班,但是如果10月8号是周日,在计算的时候,也会不考虑进去。这就比较尴尬。 另外就是10月8号是不是周末,不同年份又不同。 处理办法: 把可能产生上述问题的日期,都单独拎出来,在计算的时候,先判断是否满足这些日期,再判断这些日期是否是周末 如果不是周末,正常计算,如果是周末,还要加上当天的时间。 */ String str = String.valueOf(d1.get(Calendar.MONTH) + 1) + "-" + String.valueOf(d1.get(Calendar.DAY_OF_MONTH)); if (isHoliday.contains(str)) { return true; } return false; } //判断是否是加班日 private boolean isPlusDay(Calendar d1) { String str = String.valueOf(d1.get(Calendar.MONTH) + 1) + "-" + String.valueOf(d1.get(Calendar.DAY_OF_MONTH)); if (isPlusDau.contains(str)) { return true; } return false; } //判断是否是周末 private boolean isWeek(Calendar d1) { if (d1.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || d1.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) { return true; } return false; } //预处理开始时间 private Calendar getBeginDay(Calendar d1) { if (isHodliDays(d1)) { //如果是节假日,往后延一天,并且从这一天的00:00:00开始 d1 = addCalendar(d1, 1); return getBeginDay(d1); } else { //再判断是否是周末,如果是周末,判断是否是加班日 if (isWeek(d1)) { if (!isPlusDay(d1)) { d1 = addCalendar(d1, 1); return getBeginDay(d1); } else { return d1; } } else { return d1; } } } //预处理结束时间 private Calendar getEndDay(Calendar d2) { if (isHodliDays(d2)) { //如果是节假日,往前提一天,并且从这一天的00:00:00开始 d2 = addCalendar(d2, -1); return getEndDay(d2); } else { //不是节假日 if (isWeek(d2)) { if (!isPlusDay(d2)) { d2 = addCalendar(d2, -1); return getEndDay(d2); } else { return d2; } } else { return d2; } } } //预处理重置时分秒 private Calendar addCalendar(Calendar d, int m) { if (m == 1) { d.add(Calendar.DATE, 1); d.set(Calendar.HOUR_OF_DAY, 0);//也可直接设置为beginHour d.set(Calendar.MINUTE, 0); d.set(Calendar.SECOND, 0); } else { d.add(Calendar.DATE, -1); d.set(Calendar.HOUR_OF_DAY, 23);//也可直接设置为endHour d.set(Calendar.MINUTE, 59); d.set(Calendar.SECOND, 59); } return d; } //获取当天实际的工作时间 private long getDayMiLLI(Calendar d, boolean isBegin) { long rv = 0; int h = d.get(Calendar.HOUR_OF_DAY); if (isBegin) { if (h < afternoonEnd) { if (h >= morningBegin) { if (h >= afternoonBegin) { //计算开始那一天的时间长度 rv += (afternoonEnd - h) * 60 * 60 * 1000; rv -= d.get(Calendar.MINUTE) * 60 * 1000; rv -= d.get(Calendar.SECOND) * 1000; rv -= d.get(Calendar.MILLISECOND); } else if (h >= morningEnd && h < afternoonBegin) { rv += (afternoonEnd - afternoonBegin) * 60 * 60 * 1000; } else { rv += ((afternoonEnd - afternoonBegin) + (morningEnd - h)) * 60 * 60 * 1000; rv -= d.get(Calendar.MINUTE) * 60 * 1000; rv -= d.get(Calendar.SECOND) * 1000; rv -= d.get(Calendar.MILLISECOND); } } else { rv = ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin)) * 60 * 60 * 1000; } } } else { if (h >= morningBegin) { if (h < afternoonEnd) { if (h >= afternoonBegin) { rv += ((morningEnd - morningBegin) + (h - afternoonBegin)) * 60 * 60 * 1000; rv += d.get(Calendar.MINUTE) * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } else if (h >= morningEnd && h < afternoonBegin) { rv += (morningEnd - morningBegin) * 60 * 60 * 1000; } else { rv += (h - morningBegin) * 60 * 60 * 1000; rv += d.get(Calendar.MINUTE) * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } } else { rv = ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin)) * 60 * 60 * 1000; } } } return rv; } //核心计算函数,返回毫秒 private long getDayMiLLI(Calendar c1, Calendar c2) { long beginL = 0;//开始天时间 long endL = 0;//结束天时间 long rv = 0; //如果开始日期和结束日期不是同一天,开始往前计算 if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR) || c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH) || c1.get(Calendar.DAY_OF_MONTH) != c2 .get(Calendar.DAY_OF_MONTH)) { //不是同一天 beginL = getDayMiLLI(c1, true); endL = getDayMiLLI(c2, false); rv = beginL + endL; c1.add(Calendar.DATE, 1); while (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR) || c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH) || c1 .get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH)) { if (!isHodliDays(c1)) { if (!isWeek(c1)) { rv += ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin)) * 60 * 60 * 1000; } else { if (isPlusDay(c1)) { rv += ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin)) * 60 * 60 * 1000; } } } c1.add(Calendar.DATE, 1); } } else { //是同一天 int bh = c1.get(Calendar.HOUR_OF_DAY);//开始 int eh = c2.get(Calendar.HOUR_OF_DAY);//结束 if (bh < morningBegin) { //开始时间小于早上开始时间,就等于说及计算结束时间在这一天的实际时间 rv += getDayMiLLI(c2, false); } else { if (eh >= afternoonEnd) { //结束时间大于下午结束时间,等于就是计算开始时间在这一天的实际时间 rv += getDayMiLLI(c1, true); } else { /** * 开始和结束都在中间时间段 * 1.开始和结束都在上午 * 2.开始和结束都在下午 * 3.开始在上午,结束在下午 * 4.开始在中间,结束不在 * 5.结束在中间,开始不在 * 6.开始和结束都在中间 */ if (eh < morningEnd || bh >= afternoonBegin) { //都在上午或者都在下午 rv += (eh - bh) * 60 * 60 * 1000; rv -= c1.get(Calendar.MINUTE) * 60 * 1000; rv -= c1.get(Calendar.SECOND) * 1000; rv -= c1.get(Calendar.MILLISECOND); rv += c2.get(Calendar.MINUTE) * 60 * 1000; rv += c2.get(Calendar.SECOND) * 1000; rv += c2.get(Calendar.MILLISECOND); } else if (bh < morningEnd && eh >= afternoonBegin) { //开始在上午,结束在下午 rv += ((eh - bh) - (afternoonBegin - morningEnd)) * 60 * 60 * 1000; rv -= c1.get(Calendar.MINUTE) * 60 * 1000; rv -= c1.get(Calendar.SECOND) * 1000; rv -= c1.get(Calendar.MILLISECOND); rv += c2.get(Calendar.MINUTE) * 60 * 1000; rv += c2.get(Calendar.SECOND) * 1000; rv += c2.get(Calendar.MILLISECOND); } else if (bh < morningEnd && eh < afternoonBegin) { //开始在上午,结束在中间 rv += (morningEnd - bh) * 60 * 60 * 1000; rv -= c1.get(Calendar.MINUTE) * 60 * 1000; rv -= c1.get(Calendar.SECOND) * 1000; rv -= c1.get(Calendar.MILLISECOND); } else if (bh > morningEnd && eh >= afternoonBegin) { //开始在中间,结束在下午 rv += (eh - afternoonBegin) * 60 * 60 * 1000; rv += c2.get(Calendar.MINUTE) * 60 * 1000; rv += c2.get(Calendar.SECOND) * 1000; rv += c2.get(Calendar.MILLISECOND); } else { logger.debug("the begin time c1 " + c1.toString() + " and the end time c2 " + c2.toString() + " in not work day!"); } } } } return rv; } private Calendar getNew(Calendar begin) { begin.add(Calendar.DATE, 1); begin.set(Calendar.HOUR_OF_DAY, morningBegin); begin.set(Calendar.MINUTE, 0); begin.set(Calendar.SECOND, 0); return begin; } //核心计算函数,返回日期 private Date func(Calendar begin, double hours) { begin = getBeginDay(begin); int h = begin.get(Calendar.HOUR_OF_DAY); if (h < morningBegin) { //全天 if (hours > ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin))) { begin = getNew(begin); hours = hours - ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin)); return func(begin, hours); } else { /** * 这里要判断下,这个小时是否大于上午的工作时间,大于的话,时间就的到下午去了 */ if (hours > (morningEnd - morningBegin)) { begin.set(Calendar.HOUR_OF_DAY, afternoonBegin); hours = hours - (morningEnd - morningBegin); } else { begin.set(Calendar.HOUR_OF_DAY, morningBegin); } begin.set(Calendar.MINUTE, 0); begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); long time = begin.getTime().getTime(); hours = hours * 60 * 60 * 1000; time += hours; return new Date(time); } } else if (h >= afternoonEnd) { //过期,新增一天,重新算 begin.add(Calendar.DATE, 1); return func(begin, hours); } else { //计算 long tm = getDayMiLLI(begin, true);//今天的时间 double houts_m = hours * 60 * 60 * 1000; if (tm >= houts_m) { //不跨天,计算今天的 if (h < morningEnd) { //在上午 long rv = 0; rv += (morningEnd - h) * 60 * 60 * 1000; rv -= begin.get(Calendar.MINUTE) * 60 * 1000; rv -= begin.get(Calendar.SECOND) * 1000; rv -= begin.get(Calendar.MILLISECOND); if (houts_m > rv) { //到下午 begin.set(Calendar.HOUR_OF_DAY, afternoonBegin); begin.set(Calendar.MINUTE, 0); begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); long time = begin.getTime().getTime(); time += (houts_m - rv); return new Date(time); } else { //还在上午 long time = begin.getTime().getTime(); time += houts_m; return new Date(time); } } else if (h >= afternoonBegin) { //在下午 long time = begin.getTime().getTime(); time += houts_m; return new Date(time); } else { //在中间 begin.set(Calendar.HOUR_OF_DAY, afternoonBegin); begin.set(Calendar.MINUTE, 0); begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); long time = begin.getTime().getTime(); time += houts_m; return new Date(time); } } else { //跨天,到第二天 begin = getNew(begin); hours = (houts_m - tm) / 1000 / 60 / 60; return func(begin, hours); } } } /** * 计算两个日期之间的时间差,不算节假日、不算周末、不算非正常工作时间 *

* 设计思路: * 取开始时间,判断是否是节假日、是否是周末、是否是加班日 * 如果是节假日: * 往后+1天,再继续判断 * 如果是周末: * 判断是否是加班日,如果不是加班日,往后+1天 * * @param begin 开始时间 * @param end 结束时间 * @return 时间差,单位是毫秒 */ public long getMinusofTowDate(Calendar begin, Calendar end) { long midL = 0;//中间差值时间 // 0.预处理 begin = getBeginDay(begin); end = getEndDay(end); // 1.如果开始时间大于结束时间,交换下,同时结果返回负数即可 if (begin.after(end)) { Calendar swap = begin; begin = end; end = swap; midL = -getDayMiLLI(begin, end); } else { midL = getDayMiLLI(begin, end); } // 2.计算开始 return midL; } /** * 根据日期计算xx小时后对应日期,刨除工作日、节假日 * * @param d * @param hours * @return */ public Date getPluseHourDate(Date d, double hours) { Calendar cal_start = Calendar.getInstance(); cal_start.setTime(d); return func(cal_start, hours); } } 注:

DateCal作为一个单独的工具类提了出来,对外提供的两个方法:

public long getMinusofTowDate(Calendar begin, Calendar end) public Date getPluseHourDate(Date d, double hours) 优化点:

可以将法定节假日、是否加班日、工作时间这些变量作为配置数据从数据库中或者从配置文件中读取,这样在发生变化和更新的时候,不用重新编译发布,方便快捷。

 

20210219更新

代码做了部分优化和调整,调整点如下:

(1)上班时间支持自定义设置,包括上午开始时间、下班时间以及下午的上班时间及下班时间

(2)节假日及节假日前后的加班,提到外置,可以通过配置或者读取数据库的方式

优化后的工具类代码如下:

package com.tydic.utils; import org.apache.log4j.Logger; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class DateCal { //法定节假日 private final String isHoliday = "1-1,1-2,1-3,2-9,2-10,2-11,2-12,2-13,2-14," + "2-15,4-4,4-5,4-6,4-29,4-30,5-1,6-10,6-11," + "6-12,9-24,10-1,10-2,10-3,10-4,10-5,10-6,10-7"; //节假日前后的加班 private final String isPlusDau = "10-8"; //工作时间 private int morningBegin = 8;//上午开始时间 8点 private int morningBeginMin = 30;//分钟 0分钟 private int morningEnd = 12;//上午结束时间 12点 private int morningEndMin = 0;//分钟 0分钟 private int afternoonBegin = 14;//下午开始时间 14点 private int afternoonBeginMin = 30;//分钟 14点 private int afternoonEnd = 18;//下午结束时间 18点 private int afternoonEndMin = 0;//分钟 18点 private Logger logger = Logger.getLogger(DateCal.class); public DateCal(int morningBegin, int morningBeginMin, int morningEnd, int morningEndMin, int afternoonBegin, int afternoonBeginMin, int afternoonEnd, int afternoonEndMin) { this.morningBegin = morningBegin; this.morningBeginMin = morningBeginMin; this.morningEnd = morningEnd; this.morningEndMin = morningEndMin; this.afternoonBegin = afternoonBegin; this.afternoonBeginMin = afternoonBeginMin; this.afternoonEnd = afternoonEnd; this.afternoonEndMin = afternoonEndMin; } public static void main(String[] args) { try { String strDateStart = "2020-01-02 12:35:59"; String strDateEnd = "2020-01-02 12:36:21"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date_start = sdf.parse(strDateStart); Date date_end = sdf.parse(strDateEnd); DateCal app = new DateCal(8,30,12,0,14,30,18,0); Calendar cal_start = Calendar.getInstance(); Calendar cal_end = Calendar.getInstance(); cal_start.setTime(date_start); cal_end.setTime(date_end); //System.out.println(DateUtil.getDate(app.getPluseHourDate(date_start,2),DateUtil.TYPE4)); System.out.println(app.getMinusofTowDate(cal_start, cal_end)); } catch (Exception e) { // TODO: handle exception } } //判断是否是法定节假日 private boolean isHodliDays(Calendar d1) { /* 关于法定节假日,这里还有一个问题需要提前考虑下 例如: 国庆10月1号到10月7号,那10月8号正式上班,但是如果10月8号是周日,在计算的时候,也会不考虑进去。这就比较尴尬。 另外就是10月8号是不是周末,不同年份又不同。 处理办法: 把可能产生上述问题的日期,都单独拎出来,在计算的时候,先判断是否满足这些日期,再判断这些日期是否是周末 如果不是周末,正常计算,如果是周末,还要加上当天的时间。 */ String str = String.valueOf(d1.get(Calendar.MONTH) + 1) + "-" + String.valueOf(d1.get(Calendar.DAY_OF_MONTH)); // if (isHoliday.contains(str)) if (CommTool.getHoidayDay().contains(str)) { return true; } return false; } //判断是否是加班日 private boolean isPlusDay(Calendar d1) { String str = String.valueOf(d1.get(Calendar.MONTH) + 1) + "-" + String.valueOf(d1.get(Calendar.DAY_OF_MONTH)); //if (isPlusDau.contains(str)) if (CommTool.getPlusDay().contains(str)) { return true; } return false; } //判断是否是周末 private boolean isWeek(Calendar d1) { if (d1.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || d1.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) { return true; } return false; } //预处理开始时间 private Calendar getBeginDay(Calendar d1) { if (isHodliDays(d1)) { //如果是节假日,往后延一天,并且从这一天的00:00:00开始 d1 = addCalendar(d1, 1); return getBeginDay(d1); } else { //再判断是否是周末,如果是周末,判断是否是加班日 if (isWeek(d1)) { if (!isPlusDay(d1)) { d1 = addCalendar(d1, 1); return getBeginDay(d1); } else { return d1; } } else { return d1; } } } //预处理结束时间 private Calendar getEndDay(Calendar d2) { if (isHodliDays(d2)) { //如果是节假日,往前提一天,并且从这一天的00:00:00开始 d2 = addCalendar(d2, -1); return getEndDay(d2); } else { //不是节假日 if (isWeek(d2)) { if (!isPlusDay(d2)) { d2 = addCalendar(d2, -1); return getEndDay(d2); } else { return d2; } } else { return d2; } } } //预处理重置时分秒 private Calendar addCalendar(Calendar d, int m) { if (m == 1) { d.add(Calendar.DATE, 1); d.set(Calendar.HOUR_OF_DAY, 0);//也可直接设置为beginHour d.set(Calendar.MINUTE, 0); d.set(Calendar.SECOND, 0); } else { d.add(Calendar.DATE, -1); d.set(Calendar.HOUR_OF_DAY, 23);//也可直接设置为endHour d.set(Calendar.MINUTE, 59); d.set(Calendar.SECOND, 59); } return d; } //获取当天实际的工作时间 private long getDayMiLLI(Calendar d, boolean isBegin) { long rv = 0; int h = d.get(Calendar.HOUR_OF_DAY);//时 int m = d.get(Calendar.MINUTE);//分 if (isBegin)//开始时间取d,结束时间默认设置的下午下班时间,算一天 { if (h < afternoonEnd) { if (h >= morningBegin) { if (h >= afternoonBegin) { //开始时间在下午 rv += (afternoonEnd - h) * 60 * 60 * 1000; rv += afternoonEndMin * 60 * 1000; rv -= d.get(Calendar.MINUTE) * 60 * 1000; rv -= d.get(Calendar.SECOND) * 1000; rv -= d.get(Calendar.MILLISECOND); if (h == afternoonBegin && m < afternoonBeginMin) { rv += d.get(Calendar.MINUTE) * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); rv -= afternoonBeginMin * 60 * 1000; } } else if (h >= morningEnd && h < afternoonBegin) { //开始时间在中午午休那一段,考虑上午结束的时分秒 rv += (afternoonEnd - afternoonBegin) * 60 * 60 * 1000; rv += afternoonEndMin * 60 * 1000; rv -= afternoonBeginMin * 60 * 1000; if (h == morningEnd && m < morningEndMin) { rv += (morningEndMin - m) * 60 * 1000; rv -= d.get(Calendar.SECOND) * 1000; rv -= d.get(Calendar.MILLISECOND); } } else { rv += ((afternoonEnd - afternoonBegin) + (morningEnd - h)) * 60 * 60 * 1000; rv -= afternoonBeginMin * 60 * 1000; rv += afternoonEndMin * 60 * 1000; rv += morningEndMin * 60 * 1000; rv -= d.get(Calendar.MINUTE) * 60 * 1000; rv -= d.get(Calendar.SECOND) * 1000; rv -= d.get(Calendar.MILLISECOND); if (h == morningBegin && m < morningBeginMin) { rv += d.get(Calendar.MINUTE) * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); rv -= morningBeginMin * 60 * 1000; } } } else { //这就计算一整天就行了,因为开始时间在早上上班之间之前 rv = getOneDayMins(); } } else if (h == afternoonEnd) { if (m < afternoonEndMin) { rv += (afternoonEnd - m) * 60 * 1000; rv -= d.get(Calendar.SECOND) * 1000; rv -= d.get(Calendar.MILLISECOND); } } } else { //开始时间取默认上午上班时间,结束时间取d,算一天 if (h > morningBegin) //大于等于开始时间,才会去算工作时间 { if (h < afternoonEnd) { if (h >= afternoonBegin) { //结束时间在下午工作时间段 //先按整点算 rv += ((morningEnd - morningBegin) + (h - afternoonBegin)) * 60 * 60 * 1000; rv -= morningBeginMin * 60 * 1000;//开始分钟减去 rv += morningEndMin * 60 * 1000;//结束分钟加上 if (h == afternoonBegin) { if (m >= afternoonBeginMin) { rv += (m - afternoonBeginMin) * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } } else { rv -= afternoonBeginMin * 60 * 1000; rv += m * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } } else if (h >= morningEnd && h < afternoonBegin) { rv += (morningEnd - morningBegin) * 60 * 60 * 1000; rv -= morningBeginMin * 60 * 1000; rv += morningEndMin * 60 * 1000; if (h == morningEnd) { if (m < morningEndMin) { rv -= morningEndMin * 60 * 1000; rv += m * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } } } else { rv += (h - morningBegin) * 60 * 60 * 1000; rv -= morningBeginMin * 60 * 1000; rv += d.get(Calendar.MINUTE) * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } } else { rv = ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin)) * 60 * 60 * 1000; rv -= morningBeginMin * 60 * 1000;//开始分钟减去 rv += morningEndMin * 60 * 1000;//结束分钟加上 rv -= afternoonBeginMin * 60 * 1000;//开始分钟减去 rv += afternoonEndMin * 60 * 1000;//结束分钟加上 if (h == afternoonEnd && m < afternoonEndMin) { rv -= afternoonEndMin * 60 * 1000; rv += m * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } } } else if (h == morningBegin) { if (m >= morningBeginMin) { rv += (m - morningBeginMin) * 60 * 1000; rv += d.get(Calendar.SECOND) * 1000; rv += d.get(Calendar.MILLISECOND); } } } return rv; } //核心计算函数,返回毫秒 private long getDayMiLLI(Calendar c1, Calendar c2) { long beginL = 0;//开始天时间 long endL = 0;//结束天时间 long rv = 0; //如果开始日期和结束日期不是同一天,开始往前计算 if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR) || c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH) || c1.get(Calendar.DAY_OF_MONTH) != c2 .get(Calendar.DAY_OF_MONTH)) { //不是同一天,开始日期往前加一天,rv时间累积一天的工作时间 beginL = getDayMiLLI(c1, true); endL = getDayMiLLI(c2, false); rv = beginL + endL; c1.add(Calendar.DATE, 1); while (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR) || c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH) || c1 .get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH)) { if (!isHodliDays(c1)) //不是节假日 { //如果不是周末或者是加班日 if (!isWeek(c1) || isPlusDay(c1)) { rv += getOneDayMins(); } } c1.add(Calendar.DATE, 1); } } else { //是同一天 int bh = c1.get(Calendar.HOUR_OF_DAY);//开始小时 int m1 = c1.get(Calendar.MINUTE); int eh = c2.get(Calendar.HOUR_OF_DAY);//结束小时 int m2 = c2.get(Calendar.MINUTE); if (bh = morningBeginMin) { rv -= (m1 - morningBeginMin) * 60 * 1000; rv -= c1.get(Calendar.SECOND) * 1000; rv -= c1.get(Calendar.MILLISECOND); } } } else { if (eh >= afternoonEnd) { //结束时间大于下午结束时间,等于就是计算开始时间在这一天的实际时间 rv += getDayMiLLI(c1, true); if (eh == afternoonEnd) { if (m2 < afternoonEndMin) { rv -= (afternoonEndMin - m2) * 60 * 1000; rv += c1.get(Calendar.SECOND) * 1000; rv += c1.get(Calendar.MILLISECOND); } } } else { /** * 开始和结束都在中间时间段 * 1.开始和结束都在上午 * 2.开始和结束都在下午 * 3.开始在上午,结束在下午 * 4.开始在中间,结束不在 * 5.结束在中间,开始不在 * 6.开始和结束都在中间 */ if (eh = afternoonBegin) { //都在上午或者都在下午 rv += (eh - bh) * 60 * 60 * 1000; rv -= c1.get(Calendar.MINUTE) * 60 * 1000; rv -= c1.get(Calendar.SECOND) * 1000; rv -= c1.get(Calendar.MILLISECOND); rv += c2.get(Calendar.MINUTE) * 60 * 1000; rv += c2.get(Calendar.SECOND) * 1000; rv += c2.get(Calendar.MILLISECOND); if (bh == afternoonBegin) { if(eh==afternoonBegin && m2=morningEndMin){ rv=0; } else if (m2 >= morningEndMin) { rv -= c2.get(Calendar.MINUTE) * 60 * 1000; rv -= c2.get(Calendar.SECOND) * 1000; rv -= c2.get(Calendar.MILLISECOND); rv += morningEndMin * 60 * 1000; } } } else if (bh = afternoonBegin) { //开始在上午,结束在下午 rv += ((eh - bh) - (afternoonBegin - morningEnd)) * 60 * 60 * 1000; rv -= c1.get(Calendar.MINUTE) * 60 * 1000; rv -= c1.get(Calendar.SECOND) * 1000; rv -= c1.get(Calendar.MILLISECOND); rv += c2.get(Calendar.MINUTE) * 60 * 1000; rv += c2.get(Calendar.SECOND) * 1000; rv += c2.get(Calendar.MILLISECOND); rv += morningEndMin * 60 * 1000; rv -= afternoonBeginMin * 60 * 1000; if (eh == afternoonBegin) { if (m2 < afternoonBeginMin) { rv += afternoonBeginMin * 60 * 1000; rv -= c2.get(Calendar.MINUTE) * 60 * 1000; rv -= c2.get(Calendar.SECOND) * 1000; rv -= c2.get(Calendar.MILLISECOND); } } if (bh == morningEnd) { if (m1 >= morningEndMin) { rv += c1.get(Calendar.MINUTE) * 60 * 1000; rv += c1.get(Calendar.SECOND) * 1000; rv += c1.get(Calendar.MILLISECOND); rv -= morningEndMin * 60 * 1000; } } } else if (bh = morningEndMin) { rv += c1.get(Calendar.MINUTE) * 60 * 1000; rv += c1.get(Calendar.SECOND) * 1000; rv += c1.get(Calendar.MILLISECOND); rv -= morningEndMin * 60 * 1000; } } } else if (bh > morningEnd && eh >= afternoonBegin) { //开始在中间,结束在下午 if (eh > afternoonBegin) { rv += (eh - afternoonBegin) * 60 * 60 * 1000; rv += c2.get(Calendar.MINUTE) * 60 * 1000; rv += c2.get(Calendar.SECOND) * 1000; rv += c2.get(Calendar.MILLISECOND); } else { if (m2 >= afternoonBeginMin) { rv += (m2 - afternoonBeginMin) * 60 * 1000; rv += c2.get(Calendar.SECOND) * 1000; rv += c2.get(Calendar.MILLISECOND); } } } else { logger.debug("the begin time c1 " + c1.toString() + " and the end time c2 " + c2.toString() + " in not work day!"); } } } } return rv; } private Calendar getNew(Calendar begin) { begin.add(Calendar.DATE, 1); begin.set(Calendar.HOUR_OF_DAY, morningBegin); begin.set(Calendar.MINUTE, morningBeginMin); begin.set(Calendar.SECOND, 0); return begin; } //获取一天的实际上班时间 private int getOneDayMins() { int rv = 0; rv += ((afternoonEnd - afternoonBegin) + (morningEnd - morningBegin)) * 60 * 60 * 1000; rv -= morningBeginMin * 60 * 1000;//开始分钟减去 rv += morningEndMin * 60 * 1000;//结束分钟加上 rv -= afternoonBeginMin * 60 * 1000;//开始分钟减去 rv += afternoonEndMin * 60 * 1000;//结束分钟加上 System.out.println("---->" + rv); return rv; } //核心计算函数,返回日期 private Date func(Calendar begin, double hours) { begin = getBeginDay(begin); int h = begin.get(Calendar.HOUR_OF_DAY); int m = begin.get(Calendar.MINUTE); if (h < morningBegin) { //全天 int o_min = getOneDayMins(); if (hours > o_min) { begin = getNew(begin); hours = hours - o_min; return func(begin, hours); } else { /** * 这里要判断下,这个小时是否大于上午的工作时间,大于的话,时间就的到下午去了 */ int morning_min = (morningEnd - morningBegin) * 60 * 60 * 1000; morning_min -= morningBeginMin * 60 * 1000; morning_min += morningEndMin * 60 * 1000; if (hours > morning_min) { begin.set(Calendar.HOUR_OF_DAY, afternoonBegin); begin.set(Calendar.MINUTE, afternoonBeginMin); hours = hours - morning_min; } else { begin.set(Calendar.HOUR_OF_DAY, morningBegin); begin.set(Calendar.MINUTE, morningBeginMin); } begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); long time = begin.getTime().getTime(); time += hours; return new Date(time); } } else if (h >= afternoonEnd) { //过期,新增一天,重新算 if (h == afternoonEnd && m < afternoonEndMin) { hours -= m * 60 * 1000; hours -= begin.get(Calendar.SECOND) * 1000; hours -= begin.get(Calendar.MILLISECOND); } begin = getNew(begin); return func(begin, hours); } else { //计算 long tm = getDayMiLLI(begin, true);//今天的时间 double houts_m = hours; if (tm >= houts_m) { //不跨天,计算今天的 if (h < morningEnd) { //在上午 long rv = 0; rv += (morningEnd - h) * 60 * 60 * 1000; rv += morningEndMin * 60 * 1000; rv -= begin.get(Calendar.MINUTE) * 60 * 1000; rv -= begin.get(Calendar.SECOND) * 1000; rv -= begin.get(Calendar.MILLISECOND); if (h == morningBegin) { if (m < morningBeginMin) { rv += begin.get(Calendar.MINUTE) * 60 * 1000; rv += begin.get(Calendar.SECOND) * 1000; rv += begin.get(Calendar.MILLISECOND); rv -= morningBeginMin * 60 * 1000; begin.set(Calendar.MINUTE, morningBeginMin); begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); } } if (houts_m > rv) { //到下午 begin.set(Calendar.HOUR_OF_DAY, afternoonBegin); begin.set(Calendar.MINUTE, afternoonBeginMin); begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); long time = begin.getTime().getTime(); time += (houts_m - rv); return new Date(time); } else { //还在上午 long time = begin.getTime().getTime(); time += houts_m; return new Date(time); } } else if (h >= afternoonBegin) { if (h == afternoonBegin && m < afternoonBeginMin) { begin.set(Calendar.MINUTE, afternoonBeginMin); begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); } //在下午 long time = begin.getTime().getTime(); time += houts_m; return new Date(time); } else { //在中间 begin.set(Calendar.HOUR_OF_DAY, afternoonBegin); begin.set(Calendar.MINUTE, afternoonBeginMin); begin.set(Calendar.SECOND, 0); begin.set(Calendar.MILLISECOND, 0); long time = begin.getTime().getTime(); time += houts_m; return new Date(time); } } else { //跨天,到第二天 begin = getNew(begin); hours = houts_m - tm; return func(begin, hours); } } } /** * 计算两个日期之间的时间差,不算节假日、不算周末、不算非正常工作时间 *

* 设计思路: * 取开始时间,判断是否是节假日、是否是周末、是否是加班日 * 如果是节假日: * 往后+1天,再继续判断 * 如果是周末: * 判断是否是加班日,如果不是加班日,往后+1天 * * @param begin 开始时间 * @param end 结束时间 * @return 时间差,单位是毫秒 */ public long getMinusofTowDate(Calendar begin, Calendar end) { long midL = 0;//中间差值时间 // 0.预处理 begin = getBeginDay(begin); end = getEndDay(end); // 1.如果开始时间大于结束时间,交换下,同时结果返回负数即可 if (begin.after(end)) { Calendar swap = begin; begin = end; end = swap; midL = -getDayMiLLI(begin, end); } else { midL = getDayMiLLI(begin, end); } // 2.计算开始 return midL; } /** * 根据日期计算xx小时后对应日期,刨除工作日、节假日 * * @param d * @param hours * @return */ public Date getPluseHourDate(Date d, double hours) { Calendar cal_start = Calendar.getInstance(); cal_start.setTime(d); hours = hours * 60 * 60 * 1000; return func(cal_start, hours); } }

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3